/*
 * This program (in conjunction to send_ratelimit) illustrates 
 * how to limit the rate forwarded to the client by associating
 * token-bucket constraints with the trigger
 * Usage:
 * > recv_ratelimit <cfg_file.xml>
 * > send_ratelimit  <cfg_file.xml>
 */ 


#include <stdio.h>

#include "i3.h"
#include "i3_client_api.h"
#include "utils.h"

/* callbacks */
void receive_payload(cl_trigger *t, void* data, void *fun_ctx)
{
  long seq;

  cl_buf* clb = (cl_buf *) data;
  
  if (clb->data_len) {
    seq = ntohl(*((long *)(clb->data)));
    printf("recv. seq. #: %ld \n", seq);
  }
}

void constraint_failed(cl_trigger *t, void *data, void *fun_ctx)
{
  printf("Trigger constraint failed\n");
}

void trigger_inserted(cl_trigger *t, void *data, void *fun_ctx)
{
  printf("Trigger inserted\n");  
  /* uncomment the following call to change the token-bucket
   * constraints associated with the trigger
   */
  //  cl_trigger_ratelimit(t, TOKEN_BUCKET_BYTE, 
  //		       5000, /* token depth (in bytes) */
  //		        666, /* average rate (in bytes per second) */
  //		       5000  /* peek rate (in packets per second) --
  //			      * this parameter is ignored for now 
  //			      */
  //		       );
}

void trigger_failure(cl_trigger *t, void *data, void *fun_ctx)
{
  printf("Trigger failed\n");

  /* reinsert trigger */
  cl_insert_trigger(t, 0);
}

int i3_main_loop(char *cfg_file)
{
  ID id;   
  cl_trigger *t;
  Key key;
  
  /* initialize context */
  cl_init(cfg_file);

  /* 
   * Create and insert triggers (id, R) respectively.
   * All triggers are r-constrained 
   */
  init_id_fromstr(&id, "this is a test id");

  /* make the trigger right constrained;
   * note that right constrained triggers are subject
   * to eavesdropping and impersonation -- that's why right
   * constrained triggers are appropiate only for private triggers.
   * for public triggers use left constrained triggers
   * NOTE: key will be set to h_r(id)
   */ 
  t = cl_create_trigger(&id, ID_LEN_BITS, &key, CL_TRIGGER_CFLAG_R_CONSTRAINT);

  /* associate token-bucket constraints with the trigger */
  cl_trigger_ratelimit(t, TOKEN_BUCKET_PACKET, 
		       10, /* token depth (in packets) */
		       1,  /* average rate (in packets per second) */
		       10  /* peek rate (in packets per second) --
			    * this parameter is ignored for now 
			    */
		       );

  /* print trigger's ID */
  printf("trigger's ID: "); print_id(&id);
  /* insert trigger */
  cl_insert_trigger(t, 0);

  /* associate callbacks with the inserted trigger */
  cl_register_trigger_callback(t, CL_CBK_TRIGGER_CONSTRAINT_FAILED, 
			       constraint_failed, NULL);
  cl_register_trigger_callback(t, CL_CBK_RECEIVE_PAYLOAD, 
			       receive_payload, NULL);
  cl_register_trigger_callback(t, CL_CBK_TRIGGER_INSERTED, 
			       trigger_inserted, NULL);
  cl_register_trigger_callback(t, CL_CBK_TRIGGER_REFRESH_FAILED, 
			       trigger_failure, NULL);

  /* loop forever */
  cl_loop();

  /* remove & destroy trigger */
  cl_destroy_trigger(t);
  
  /* destroy context */
  cl_exit();
}


int main(int argc, char **argv)
{
  if (argc != 2) {
    printf("%s <cfg_file.xml>\n", argv[0]);
    exit(-1);
  }

  i3_main_loop(argv[1]);
  return -1;
}

